﻿using DidaCode.Workflow.NodeAttribute;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DidaCode.Workflow.Help
{
    internal class PropertyHelp
    {
        // 缓存属性信息和委托
        private static readonly ConcurrentDictionary<Type, PropertyMetadata[]> _typePropertyCache = new();

        // 属性元数据
        public class PropertyMetadata
        {
            public string AttributeName { get; }
           
            public Action<object, object> Setter { get; }
       
            public Func<object, object?> Getter { get; }
            public PropertyMetadata(string attributeName, Action<object, object> setter, Func<object, object?> getter)
            {
                AttributeName = attributeName;
                Setter = setter;
                Getter = getter;
            }
        }

        /// <summary>
        /// 获取类型的缓存属性元数据
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>属性元数据数组</returns>
        public static PropertyMetadata[] GetCachedProperties(Type type)
        {
            return _typePropertyCache.GetOrAdd(type, t =>
            {
                return t.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(prop => Attribute.IsDefined(prop, typeof(AutoMapAttribute)))
                    .Select(prop =>
                    {
                        var attribute = (AutoMapAttribute)Attribute.GetCustomAttribute(prop, typeof(AutoMapAttribute));
                        var setter = CreateSetter(prop);
                        var getter = CreateGetter(prop);
                        return new PropertyMetadata(attribute.Name, setter, getter);
                    })
                    .ToArray();
            });
        }

        /// <summary>
        /// 创建属性的 Setter 委托
        /// </summary>
        /// <param name="property">属性信息</param>
        /// <returns>Setter 委托</returns>
        private static Action<object, object> CreateSetter(PropertyInfo property)
        {
            var target = Expression.Parameter(typeof(object));
            var value = Expression.Parameter(typeof(object));
            var body = Expression.Assign(
                Expression.Property(Expression.Convert(target, property.DeclaringType), property),
                Expression.Convert(value, property.PropertyType));
            return Expression.Lambda<Action<object, object>>(body, target, value).Compile();
        }

        /// <summary>
        /// 创建属性的 Getter 委托
        /// </summary>
        /// <param name="property">属性信息</param>
        /// <returns>Getter 委托</returns>
        private static Func<object, object?> CreateGetter(PropertyInfo property)
        {
            var target = Expression.Parameter(typeof(object));
            var body = Expression.Convert(
                Expression.Property(Expression.Convert(target, property.DeclaringType), property),
                typeof(object));
            return Expression.Lambda<Func<object, object?>>(body, target).Compile();
        }
    }
}
